﻿using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Account.Public.Web.Areas.Account.Controllers.Models;
using Volo.Abp.Identity;
using Volo.Abp.Validation;
using IdentityUser = Volo.Abp.Identity.IdentityUser;

namespace Volo.Abp.Account.Public.Web.Areas.Account.Controllers
{
	[Area("account")]
	[ControllerName("Login")]
	[Route("api/account")]
	[Controller]
	[RemoteService(true, Name = "AbpAccountPublic")]
	public class AccountController : AccountControllerBase
	{
		protected SignInManager<IdentityUser> SignInManager { get; }

		protected IdentityUserManager UserManager { get; }

		public AccountController(SignInManager<IdentityUser> signInManager, IdentityUserManager userManager)
		{
			this.SignInManager = signInManager;
			this.UserManager = userManager;
		}

		[Route("login")]
		[HttpPost]
		public virtual async Task<AbpLoginResult> Login(Volo.Abp.Account.Public.Web.Areas.Account.Controllers.Models.UserLoginInfo login)
		{
			this.ValidateLoginInfo(login);
			await this.ReplaceEmailToUsernameOfInputIfNeeds(login);
			var signInResult = await this.SignInManager.PasswordSignInAsync(login.UserNameOrEmailAddress, login.Password, login.RememberMe, true);
			return GetLoginResult(signInResult);
		}

		[Route("logout")]
		[HttpGet]
		public virtual async Task Logout()
		{
			await this.SignInManager.SignOutAsync();
		}

		[HttpPost]
		[Route("checkPassword")]
		public virtual async Task<AbpLoginResult> CheckPassword(Volo.Abp.Account.Public.Web.Areas.Account.Controllers.Models.UserLoginInfo login)
		{
			this.ValidateLoginInfo(login);
			await this.ReplaceEmailToUsernameOfInputIfNeeds(login);
			var identityUser = await this.UserManager.FindByNameAsync(login.UserNameOrEmailAddress);
			if (identityUser == null)
			{
				identityUser = await this.UserManager.FindByEmailAsync(login.UserNameOrEmailAddress);
			}
			return GetLoginResult(await this.SignInManager.CheckPasswordSignInAsync(identityUser, login.Password, true));
		}

		private static AbpLoginResult GetLoginResult(Microsoft.AspNetCore.Identity.SignInResult signInResult)
		{
			if (signInResult.IsLockedOut)
			{
				return new AbpLoginResult(LoginResultType.LockedOut);
			}
			if (signInResult.RequiresTwoFactor)
			{
				return new AbpLoginResult(LoginResultType.RequiresTwoFactor);
			}
			if (signInResult.IsNotAllowed)
			{
				return new AbpLoginResult(LoginResultType.NotAllowed);
			}
			if (!signInResult.Succeeded)
			{
				return new AbpLoginResult(LoginResultType.InvalidUserNameOrPassword);
			}
			return new AbpLoginResult(LoginResultType.Success);
		}

		protected virtual void ValidateLoginInfo(Volo.Abp.Account.Public.Web.Areas.Account.Controllers.Models.UserLoginInfo login)
		{
			if (login == null)
			{
				throw new ArgumentException("login");
			}
			if (AbpStringExtensions.IsNullOrEmpty(login.UserNameOrEmailAddress))
			{
				throw new ArgumentNullException("UserNameOrEmailAddress");
			}
			if (AbpStringExtensions.IsNullOrEmpty(login.Password))
			{
				throw new ArgumentNullException("Password");
			}
		}

		protected virtual async Task ReplaceEmailToUsernameOfInputIfNeeds(Volo.Abp.Account.Public.Web.Areas.Account.Controllers.Models.UserLoginInfo login)
		{
			if (ValidationHelper.IsValidEmailAddress(login.UserNameOrEmailAddress))
			{
				var identityUser = await this.UserManager.FindByNameAsync(login.UserNameOrEmailAddress);
				if (identityUser == null)
				{
					var result = await this.UserManager.FindByEmailAsync(login.UserNameOrEmailAddress);
					if (result != null)
					{
						login.UserNameOrEmailAddress = result.UserName;
					}
				}
			}
		}
	}
}
